﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BaseCardTypes = Wormhole.Engine.CardLibrary.BaseCardTypes;
using CardTypes = Wormhole.Engine.CardLibrary.CardTypes;
using CardProperties = Wormhole.Engine.CardLibrary.CardProperties;

namespace Wormhole.Engine.Turn
{
	/// <author>Hannes Foulds</author>
	/// <date>14 April 2008</date>
	/// <summary>
	/// This class is used to keep track of game turns.
	/// </summary>
	public class GameTurn
	{
		#region Delegates
		/// <summary>
		/// The delegate for the event which is raised when the turn is started.
		/// </summary>
		public delegate void TurnStartedDelegate();

		/// <summary>
		/// The delegate for the event which is fired when the next phase started.
		/// </summary>
		public delegate void NextPhaseStartedDelegate();

		/// <summary>
		/// This delegate is used for events that indicate that certain actions have been completed.
		/// </summary>
		public delegate void ActionCompleteDelegate(GameTurnAction action);
		#endregion

		#region Events
		/// <summary>
		/// This event is raised when a new phase starts.
		/// </summary>
		public event GamePhases.PhaseStartDelegate PhaseStart;

		/// <summary>
		/// This event is raised when the turn is started.
		/// </summary>
		public event TurnStartedDelegate TurnStarted;

		/// <summary>
		/// This event is raised to notify listeners of various completed events.
		/// </summary>
		public event ActionCompleteDelegate ActionCompleted;

		#endregion

		#region Properties

		#region Game Phases
		/// <summary>
		/// A collection of the game phases.
		/// </summary>
		protected GamePhases gamePhases;
		#endregion

		#region Game
		private Game _game;
		/// <summary>
		/// The engine game object
		/// </summary>
		public Game Game 
		{
			get
			{
				return this._game;
			}

			set
			{
				if (value != this._game)
				{
					this._game = value;
					this.SetEngineEvents();
				}
			}
		}
		#endregion

		#region Hero Player
		/// <summary>
		/// The current hero player
		/// </summary>
		public Player.Player HeroPlayer { get; set; }
		#endregion

		#region Villian Player
		/// <summary>
		/// The current villian player
		/// </summary>
		public Player.Player VillianPlayer { get; set; }
		#endregion

		#region Current Phase
		/// <summary>
		/// The current game phase being played.
		/// </summary>
		public Phase CurrentPhase 
		{
			get
			{
				return this.gamePhases.CurrentPhase.PhaseType;
			}
		}
		#endregion

		#region Player1 Actions
		/// <summary>
		/// Count the Player1 actions that was performed.
		/// </summary>
		protected int Player1Actions { get; set; }
		#endregion

		#region Player2 Actions
		/// <summary>
		/// Count the Player2 actions that was performed.
		/// </summary>
		protected int Player2Actions { get; set; }

		#endregion


		public bool AllowEmptyResponse { get; set; }
		#endregion

		#region Constructor
		/// <summary>
		/// Initialize a new instance of the class.
		/// </summary>
		/// <param name="game">The game engine object.</param>
		public GameTurn(Game game)
		{
			// create the game phases object
			this.gamePhases = new GamePhases();
			this.gamePhases.PhaseStart += new GamePhases.PhaseStartDelegate(gamePhases_PhaseStart);
			
			// set the game engine object
			this.Game = game;
		}
		#endregion

		#region On Phase Start
		/// <summary>
		/// Raise the phase start event.
		/// </summary>
		/// <param name="phase">The phase that was started.</param>
		protected void OnPhaseStart(GamePhase phase)
		{
			// process the phase that was started
			switch (phase.PhaseType)
			{
				case Phase.Power:
					this.ProcessPowerPhase();
					break;
				case Phase.Mission:
					this.ProcessMissionPhase();
					break;
				case Phase.PerformAction:
					this.ProcessPerformActionPhase();
					break;
				case Phase.ResolveMission:
					this.ProcessResolveMissionPhase();
					break;
				case Phase.DecideContinue:
					this.ProcessDecideContinuePhase();
					break;
				case Phase.Debrief:
					this.ProcessDebriefPhase();
					break;
				case Phase.EndOfTurn:
					this.ProcessEndOfTurnPhase();
					break;
			}

			// raise the event
			if (this.PhaseStart != null)
				this.PhaseStart(phase);
		}
		#endregion

		#region Set Engine Events
		/// <summary>
		/// Wire up events for the engine objects.
		/// </summary>
		protected void SetEngineEvents()
		{
			this.Game.Player1.CardsInHand.CardPlayed += new Wormhole.Engine.Decks.HandCards.CardPlayedDelegate(Player1CardsInHand_CardPlayed);
			this.Game.Player2.CardsInHand.CardPlayed += new Wormhole.Engine.Decks.HandCards.CardPlayedDelegate(Player2CardsInHand_CardPlayed);

			this.Game.Player1.UnassignedSupport.CardAssigned += new Wormhole.Engine.CardLibrary.BaseCardTypes.SkillsCard.CardAssignedDelegate(Player1_CardAssigned);
			this.Game.Player2.UnassignedSupport.CardAssigned += new Wormhole.Engine.CardLibrary.BaseCardTypes.SkillsCard.CardAssignedDelegate(Player2_CardAssigned);

			this.Game.Player1.Team.CardAssigned += new Wormhole.Engine.CardLibrary.BaseCardTypes.SkillsCard.CardAssignedDelegate(Player1_CardAssigned);
			this.Game.Player2.Team.CardAssigned += new Wormhole.Engine.CardLibrary.BaseCardTypes.SkillsCard.CardAssignedDelegate(Player2_CardAssigned);
		}
		#endregion

		#region Event Handlers

		#region Phase Start
		/// <summary>
		/// Handle the event when a new phase is started.
		/// </summary>
		/// <param name="phase">The phase that was started.</param>
		private void gamePhases_PhaseStart(GamePhase phase)
		{
			this.OnPhaseStart(phase);
		}
		#endregion

		#region Action Counting
		void Player1CardsInHand_CardPlayed(Wormhole.Engine.CardLibrary.BaseCardTypes.Card card)
		{
			if (!(card is CardLibrary.CardTypes.Mission))
			{
				this.Player1Actions++;

				// when an action is performed, allow the opponent to respond
				if (this.CurrentPhase == Phase.PerformAction)
				{
					this.Game.Player2.GivePriority();
					this.ProcessPerformActionPhase();
				}
			}
		}

		void Player2CardsInHand_CardPlayed(Wormhole.Engine.CardLibrary.BaseCardTypes.Card card)
		{
			if (!(card is CardLibrary.CardTypes.Mission))
			{
				this.Player2Actions++;

				// when an action is performed, allow the opponent to respond
				if (this.CurrentPhase == Phase.PerformAction)
				{
					this.Game.Player1.GivePriority();
					this.ProcessPerformActionPhase();
				}
			}
		}

		void Player1_CardAssigned(Wormhole.Engine.CardLibrary.BaseCardTypes.SkillsCard card)
		{
			this.Player1Actions++;

			// when an action is performed, allow the opponent to respond
			if (this.CurrentPhase == Phase.PerformAction)
			{
				this.Game.Player2.GivePriority();
				this.ProcessPerformActionPhase();
			}
		}

		void Player2_CardAssigned(Wormhole.Engine.CardLibrary.BaseCardTypes.SkillsCard card)
		{
			this.Player2Actions++;

			// when an action is performed, allow the opponent to respond
			if (this.CurrentPhase == Phase.PerformAction)
			{
				this.Game.Player1.GivePriority();
				this.ProcessPerformActionPhase();
			}
		}

		#endregion

		#endregion

		#region Start Turn
		/// <summary>
		/// Start at the first phase.
		/// </summary>
		public void StartTurn()
		{
			this.AllowCardActions(this.HeroPlayer, false);
			this.AllowCardActions(this.VillianPlayer, false);
			this.gamePhases.StartTurn();

			// raise the event
			this.OnTurnStarted();
		}
		#endregion

		#region On Turn Started
		/// <summary>
		/// Raise the turn started event.
		/// </summary>
		protected void OnTurnStarted()
		{
			if (this.TurnStarted != null)
				this.TurnStarted();
		}
		#endregion

		#region Next Phase
		/// <summary>
		/// Proceed to the next phase.
		/// </summary>
		public void NextPhase()
		{
			this.gamePhases.NextPhase();
		}
		#endregion

		#region Process Power Phase
		/// <summary>
		/// Process the power phase.
		/// </summary>
		protected void ProcessPowerPhase()
		{
			// each player receive 3 power
			this.HeroPlayer.Power = 3;
			this.VillianPlayer.Power = 3;
			
			// move to the next phase
			this.NextPhase();
		}
		#endregion

		#region Process Mission Phase
		/// <summary>
		/// Process the mission phase.
		/// </summary>
		protected void ProcessMissionPhase()
		{
			this.Player1Actions = 0;
			this.Player2Actions = 0;

			this.AllowEmptyResponse = true;
			this.HeroPlayer.GivePriority();

			this.HeroPlayer.Missions.PlayMission();
			this.NextPhase();
		}
		#endregion

		#region Process Perform Action Phase
		/// <summary>
		/// Process the action phase.
		/// </summary>
		internal void ProcessPerformActionPhase()
		{
			// allow the card actions
			this.AllowCardActions(this.HeroPlayer, true);
			this.AllowCardActions(this.VillianPlayer, true);

			// display the input message
			if (this.Game.Player1.HasPriority)
				this.Game.Player1.UserInput.PerformActionInput(new Input.Request.CallbackDelegate(this.PassActionPhase));
			else
				this.Game.Player1.UserInput.DisplayMessage("Please wait for the player to perform an action.");
		}
		#endregion

		#region Pass Action Phase
		/// <summary>
		/// Pass in the action phase.
		/// </summary>
		/// <param name="response">The response received from the user.</param>
		internal void PassActionPhase(Input.Response response)
		{
			// complete on pass, or allow more actions
			if ((this.Player1Actions == 0) && (this.Player2Actions == 0) && (!this.AllowEmptyResponse) )
			{
				//if (this.HeroPlayer == this.Game.Player1)
					this.OnActionCompleted(GameTurnAction.Pass);
				
				this.CompleteActionPhase(response);
			}
			else
			{
				if (this.Game.Player1.HasPriority)
				{
					this.Game.Player2.GivePriority();
					this.Player2Actions = 0;
					this.Player1Actions = 0;
					this.OnActionCompleted(GameTurnAction.Pass);
				}
				else
				{
					this.Game.Player1.GivePriority();
					//this.Player1Actions = 0;
				}

				this.AllowEmptyResponse = false;
				this.ProcessPerformActionPhase();
			}
		}
		#endregion

		#region Complete Action Phase
		/// <summary>
		/// Complete the action phase.
		/// </summary>
		/// <param name="response">The response received from the user.</param>
		private void CompleteActionPhase(Input.Response response)
		{
			this.AllowCardActions(this.HeroPlayer, false);
			this.AllowCardActions(this.VillianPlayer, false);
			this.NextPhase();
		}
		#endregion

		#region Process Resolve Mission Phase
		/// <summary>
		/// Resolve the mission.
		/// </summary>
		protected void ProcessResolveMissionPhase()
		{
			this.Game.Mission.Resolve();
		}
		#endregion

		#region Complete Mission Phase
		/// <summary>
		/// Complete the mission phase.
		/// </summary>
		/// <param name="success">True if the mission was successful</param>
		internal void CompleteMissionPhase(bool success)
		{
			this.NextPhase();
		}
		#endregion

		#region Disallow Card Actions
		/// <summary>
		/// Do not allow a player to perform any card actions.
		/// </summary>
		/// <param name="player">The player to disallow actions for.</param>
		/// <param name="allow">Should card actions be allowed.</param>
		protected void AllowCardActions(Player.Player player, bool allow)
		{
			player.CardsInHand.SetAllowPlay(allow);
			player.Team.SetAllowAssign(allow);
			player.UnassignedSupport.SetAllowAssign(allow);
			player.UnassignedAversaries.SetAllowAssign(allow);
		}
		#endregion

		#region Process Decide to Continue Phase
		/// <summary>
		/// As the user if he would like to attempt another mission.
		/// </summary>
		protected void ProcessDecideContinuePhase()
		{
			this.AllowCardActions(this.HeroPlayer, false);
			this.AllowCardActions(this.VillianPlayer, false);

			if (this.HeroPlayer == this.Game.Player1)
				this.HeroPlayer.UserInput.PlayAnotherMissionInput(new Input.Request.CallbackDelegate(this.CompleteProcessDecideContinuePhase));
			else
				this.Game.Player1.UserInput.DisplayMessage("Please wait while the opponent decides on playing another mission.");
		}
		#endregion

		#region Complete Decide to Continue Phase
		/// <summary>
		/// Complete the decide to continue phase.
		/// </summary>
		/// <param name="response">The response received from the user.</param>
		internal void CompleteProcessDecideContinuePhase(Input.Response response)
		{
			if (response.ResponseType == Wormhole.Engine.Input.ResponseType.Yes)
			{
				this.OnActionCompleted(GameTurnAction.ContinueMissions);
				this.StartNewMission();
			}
			else if (response.ResponseType == Wormhole.Engine.Input.ResponseType.No)
			{
				this.OnActionCompleted(GameTurnAction.StopMissions);
				this.NextPhase();
			}
		}
		#endregion

		#region Start New Mission
		/// <summary>
		/// Start a new mission.
		/// </summary>
		public void StartNewMission()
		{
			this.gamePhases.GotoPhase(Phase.Mission);
		}
		#endregion

		#region Process Debrief Phase
		/// <summary>
		/// Process the debrief phase.
		/// </summary>
		protected void ProcessDebriefPhase()
		{
			this.AllowCardActions(this.HeroPlayer, false);
			this.AllowCardActions(this.VillianPlayer, false);

			if (this.Game.Mission.FailedMissions.Count > 0)
				this.Game.Mission.ReplaceFailedMissions();
			else
				this.CompleteDebriefPhase();
		}
		#endregion

		#region Complete Debrief Phase
		/// <summary>
		/// Complete the Debrief Phase.
		/// </summary>
		internal void CompleteDebriefPhase()
		{
			this.AllowCardActions(this.HeroPlayer, false);
			this.AllowCardActions(this.VillianPlayer, false);

			this.NextPhase();
		}
		#endregion

		#region Process End Of Turn Phase
		/// <summary>
		/// Process the end of turn phase.
		/// </summary>
		private void ProcessEndOfTurnPhase()
		{
			if (this.Game.Player1 == this.HeroPlayer)
				this.HeroPlayer.UserInput.SelectSingleCardInput(null, "End of Turn", null);
			else
				this.Game.Player1.UserInput.DisplayMessage("End of Turn");
		}
		#endregion

		#region On Action Completed
		/// <summary>
		/// Raise the action completed event.
		/// </summary>
		/// <param name="action">The action that was completed.</param>
		protected void OnActionCompleted(GameTurnAction action)
		{
			if (this.ActionCompleted != null)
				this.ActionCompleted(action);
		}
		#endregion
	}
}
